use std::any::Any;

use crate::id::IdPath;
use crate::widget::{AnyWidget, ChangeFlags};
use crate::{id::Id, message::EventResult};

pub struct Cx {
    pub(crate) id_path: IdPath,
}

impl Cx {
    pub fn with_id<T>(&mut self, id: Id, f: impl FnOnce(&mut Self) -> T) -> T {
        self.id_path.push(id);
        let result = f(self);
        self.id_path.pop();
        result
    }

    pub fn with_new_id<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> (Id, T) {
        let id = Id::next();
        self.id_path.push(id);
        let result = f(self);
        (self.id_path.pop().unwrap(), result)
    }
}

pub trait View<T, A = ()> {
    type State;
    type Element: AnyWidget;

    fn build(&self, cx: &mut Cx) -> (Id, Self::State, Self::Element);

    fn rebuild(
        &self,
        prev: &Self,
        cx: &mut Cx,
        id: &mut Id,
        state: &mut Self::State,
        element: &mut Self::Element,
    ) -> ChangeFlags;

    fn message(
        &self,
        id_path: &[Id],
        state: &mut Self::State,
        event: Box<dyn Any>,
        app_state: &mut T,
    ) -> EventResult<A>;
}
